import axios, { AxiosRequestConfig, Canceler } from 'axios'
import { isFunction } from '@/utils/is'

/** 声明一个 Map 用于存储每个请求的标识(key => url) 和 取消函数(value => Canceler) */
const pending = new Map<string, Canceler>()

/** 序列化参数 */
export const getPendingUrl = (config: AxiosRequestConfig) =>
  [
    config.url,
    config.method,
    JSON.stringify(config.data),
    JSON.stringify(config.params)
  ].join('&')

export class AxiosCanceler {
  /**
   * @description: 添加请求
   * @param {Object} config
   */
  addPending(config: AxiosRequestConfig) {
    /** 添加之前移除之前的请求 */
    this.removePending(config)

    const url = getPendingUrl(config)

    config.cancelToken =
      config.cancelToken ||
      new axios.CancelToken((cancel) => {
        /** 如果 pending 中不存在当前请求，则添加进去 */
        if (!pending.has(url)) {
          pending.set(url, cancel)
        }
      })
  }

  /**
   * @description: 移除请求
   * @param {Object} config
   */
  removePending(config: AxiosRequestConfig) {
    const url = getPendingUrl(config)

    /** 如果在 pending 中存在当前请求标识，需要取消当前请求，并且移除 */
    if (pending.has(url)) {
      const cancel = pending.get(url)
      /** 取消请求 */
      cancel && cancel()

      /** 移除当前请求 */
      pending.delete(url)
    }
  }

  /**
   * @description: 清空所有pending
   */
  clearPending() {
    /** 取消请求 */
    for (const [url, cancel] of pending) {
      cancel && isFunction(cancel) && cancel(url)
    }
    /** 清空请求 */
    pending.clear()
  }
}
